#include "nvidiagpumonitor.h"
#include <QProcess>
#include <optional>
#include <QString>
#include <QStringList>
#include <cmath>


NVGpuMonitor::NVGpuMonitor()
{

}

NVGpuMonitor::~NVGpuMonitor()
{

}



std::optional<double> NVGpuMonitor::getGpuCoreUsage()
{
    QProcess process;
    process.start("nvidia-smi", {"--query-gpu=utilization.gpu",
                                 "--format=csv,noheader,nounits"});
    process.waitForFinished();

    QString usage_str = QString(process.readAllStandardOutput());
    bool ok = false;
    double usage = usage_str.toDouble(&ok);

    if (!ok || usage < 0.0 || usage > 100.0 || std::isnan(usage)) {
        return std::nullopt;
    }

    return usage;
}

std::optional<double> NVGpuMonitor::getGpuMemUsage()
{
    QProcess process;
    process.start("nvidia-smi", {"--query-gpu=memory.used,memory.total",
                                 "--format=csv,noheader,nounits"});
    process.waitForFinished();

    QStringList parts = QString(process.readAllStandardOutput()).trimmed().split(',');
    if (parts.size() >= 2) {
        bool ok1 = false, ok2 = false;
        double used_mem = parts[0].trimmed().toDouble(&ok1);
        double total_mem = parts[1].trimmed().toDouble(&ok2);

        if (!ok1 || !ok2 || total_mem <= 0.0 || std::isnan(used_mem) || std::isnan(total_mem)) {
            return std::nullopt;
        }

        double usage = (used_mem / total_mem) * 100.0;
        if (usage < 0.0 || usage > 100.0) {
            return std::nullopt;
        }

        return usage;
    }

    return std::nullopt;
}

std::optional<double> NVGpuMonitor::getGpuCoreTemp()
{
    QProcess process;
    process.start("nvidia-smi", {"--query-gpu=temperature.gpu",
                                 "--format=csv,noheader,nounits"});
    process.waitForFinished();

    if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {
        return std::nullopt;
    }

    QString temp_str = QString(process.readAllStandardOutput()).trimmed();
    bool ok = false;
    double temperature = temp_str.toDouble(&ok);

    if (!ok || temperature < 0.0 || temperature > 150.0 || std::isnan(temperature)) {
        return std::nullopt;
    }

    return temperature;
}
